package com.xavier.dong.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author XavierDong
 **/
public class NIOServer {

    public static void main(String[] args) {

        // 创建 ServerSocketChannel

        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {

            // 得到一个 Selector
            Selector selector = Selector.open();

            // 绑定一个端口 6666 ,在服务器监听
            serverSocketChannel.socket().bind(new InetSocketAddress(6666));

            // 设置为 非阻塞
            serverSocketChannel.configureBlocking(false);

            // 把 ServerSocketChannel 注册到 selector 关心 事件为 OP_ACCEPT
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("注册的 selectionkey 数量=" + selector.keys().size()); // 1

            // 循环等待客户端连接
            while (true) {

                // 这里等待了 1 秒，如果没有 事件 发生， 返回
                if (selector.select(1000) == 0) {
                    // 没有事件发生
                    System.out.println("服务器等待了 1 秒， 无连接");
                    continue;
                }

                // 如果返回的 > 0 , 获取到 相关的 SelectionKey 集合
                // 1. 表示已经 获取到 关注事件了
                // 2. selector.selectedKeys() 返回关注事件的集合
                // 通过 selectedKeys 反向获取通道
                Set<SelectionKey> selectionKeys = selector.selectedKeys();

                // 遍历
                Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
                while (selectionKeyIterator.hasNext()) {

                    // 获取到 SelectionKey
                    SelectionKey selectionKey = selectionKeyIterator.next();

                    // 根据 SelectionKey 对应的通道 发生的事件做不同的处理
                    if (selectionKey.isAcceptable()) {
                        // 如果是 OP_ACCEPT 事件, 代表 客户端连接了
                        // 给 该 客户端 生成一个 SocketChannel
                        SocketChannel socketChannel = serverSocketChannel.accept();

                        System.out.println("客户端连接成功 生成了 一个 SocketChannel SocketChannel= " + socketChannel.hashCode());

                        // 设置为 非阻塞，不然会报 异常 IllegalBlockingModeException
                        socketChannel.configureBlocking(false);

                        // 将 当前的 SocketChannel 也注册到 Selector 上.关注事件 OP_READ。 同时给 SocketChannel 关联一个 Buffer
                        socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));

                        System.out.println("客户端连接后，注册的 selectionkey 数量=" + selector.keys().size()); // 2,3,4

                    }

                    if (selectionKey.isReadable()) {
                        // 发生了 OP_READ 事件
                        // 通过 SelectionKey 反向 获取 channel
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

                        // 获取到 该 channel 关联的 Buffer
                        ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
                        socketChannel.read(buffer);

                        System.out.println(" from 客户端发送的数据 " + new String(buffer.array()));
                    }

                    // 手动从 集合中 删除 当前的 SelectionKey  防止重复操作
                    selectionKeyIterator.remove();

                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
